package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;
import sun.nio.cs.ext.MacArabic;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitService rabbitService;

    @Value("${ware.url}")
    private String WARE_URL;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long saveOrderInfo(OrderInfo orderInfo) {
        orderInfo.sumTotalAmount();//计算总价格
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());//支付状态
        //随机生成不重复的流水号
        String outTradeNo = "LHZ" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setCreateTime(new Date());
        //过期时间定为1天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());//失效时间
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());//进度状态
        orderInfo.setTradeBody("你好，树哥！");
        orderInfoMapper.insert(orderInfo);

        //插入订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        orderDetailList.forEach(orderDetail -> {
            //订单id
            orderDetail.setOrderId(orderInfo.getId());
            orderDetailMapper.insert(orderDetail);
        });
        //获取订单id
        Long orderId = orderInfo.getId();

        //发送延时队列，如果订单未定时支付，取消订单
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,
                MqConst.ROUTING_ORDER_CANCEL, orderInfo.getId(), MqConst.DELAY_TIME);
        return orderId;
    }

    @Override
    public String getTradeNo(String userId) {
        //生成一个流水号
        String tradeNo = UUID.randomUUID().toString();
        //key
        String tradeNoKey = "tradeNo:" + userId;
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);
        //放入缓存
        return tradeNo;
    }

    @Override
    public Boolean checkTradeNo(String tradeNo, String userId) {
        String tradeNoKey = "tradeNo:" + userId;
        String tradeNoRedis = (String) redisTemplate.opsForValue().get(tradeNoKey);
        //对比缓存和后台页面的流水号
        return tradeNo.equals(tradeNoRedis);
    }

    @Override
    public void delTradeNo(String userId) {
        String tradeNoKey = "tradeNo:" + userId;
        redisTemplate.delete(tradeNoKey);
    }

    @Override
    public Boolean checkStock(Long skuId, Integer skuNum) {
        // 远程调用http://localhost:9001/hasStock?skuId=10221&num=2
//        http://localhost:9001/hasStock
        String result = HttpClientUtil.doGet(WARE_URL + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);
    }

    @Override
    public IPage<OrderInfo> getPage(Page<OrderInfo> pageParam, String userId) {
        IPage<OrderInfo> page = orderInfoMapper.getPage(pageParam, userId);
        //取出分页信息  遍历状态名
        page.getRecords().stream().forEach(item -> {
            item.setOrderStatusName(OrderStatus.getStatusNameByStatus(item.getOrderStatus()));
        });
        return page;
    }

    /**
     * 取消订单
     *
     * @param orderId
     */
    @Override
    public void execExpiredOrder(Long orderId) {
        // orderInfo
        updateOrderStatus(orderId, ProcessStatus.CLOSED);
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        updateOrderStatus(orderId, ProcessStatus.CLOSED);
        if ("2".equals(flag)){
            //发送消息队列,关闭支付宝交易记录
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        QueryWrapper<OrderDetail> orderDetailQueryWrapper = new QueryWrapper<>();
        orderDetailQueryWrapper.eq("order_id", orderId);
        List<OrderDetail> detailList = orderDetailMapper.selectList(orderDetailQueryWrapper);
        orderInfo.setOrderDetailList(detailList);
        return orderInfo;
    }

    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setProcessStatus(processStatus.name());
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        //给仓库发消息，修改订单状态为已通知仓储
        updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);
        String wareJson = initWareOrder(orderId);
        //发送消息给仓库
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK, MqConst.ROUTING_WARE_STOCK, wareJson);
        //发送消息给支付  如果支持多种支付方式,可以传入map
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
    }

    @Override
    public List<OrderInfo> orderSplit(Long orderId, String wareSkuMap) {
         /*
    1.  先获取到原始订单 107
    2.  将wareSkuMap 转换为我们能操作的对象 [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        方案一：class Param{
                    private String wareId;
                    private List<String> skuIds;
                }
        方案二：看做一个Map mpa.put("wareId",value); map.put("skuIds",value)

    3.  创建一个新的子订单 108 109 。。。
    4.  给子订单赋值
    5.  保存子订单到数据库
    6.  修改原始订单的状态
    7.  测试
     */
        // 子订单添加到集合中！
        List<OrderInfo> orderInfoArrayList=new ArrayList<>();
        OrderInfo orderInfo = getOrderInfo(orderId);//订单id
        ///parseArray 转为 list<map>
        List<Map> maps = JSON.parseArray(wareSkuMap, Map.class);//库存明细 仓库编号与商品的对照关系
        if (!CollectionUtils.isEmpty(maps)){
            for (Map map : maps) {
                String wareId = (String) map.get("wareId");//仓库id
                List<String> skuIds = (List<String>) map.get("skuIds");//一个仓库对应多个商品
                OrderInfo subOrderInfo = new OrderInfo();
                //只需改动部分值,属性拷贝
                BeanUtils.copyProperties(orderInfo,subOrderInfo);
                //防止主键冲突
                subOrderInfo.setId(null);
                //拆单后对应的主单id
                subOrderInfo.setParentOrderId(orderId);
                //赋值仓库id
                subOrderInfo.setWareId(wareId);

                //计算子订单的金额：必须有订单明细
                //获取到子订单明细
                //声明一个集合来储存订单明细
                List<OrderDetail> orderDetails=new ArrayList<>();
                List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
                // 表示主主订单明细中获取到子订单的明细
                if (!CollectionUtils.isEmpty(orderDetailList)){
                    for (OrderDetail orderDetail : orderDetailList) {
                        // 获取子订单明细的商品Id
                        for (String skuId : skuIds) {
                            if (orderDetail.getSkuId().compareTo(Long.parseLong(skuId))==0){
                                // 将订单明细添加到集合
                                orderDetails.add(orderDetail);
                            }
                        }
                    }
                }
                //给子订单赋值
                subOrderInfo.setOrderDetailList(orderDetails);
                //计算总金额
                subOrderInfo.sumTotalAmount();
                //保存子订单
                saveOrderInfo(subOrderInfo);
                //将子订单添加到集合中
                orderInfoArrayList.add(subOrderInfo);
            }
        }
        //修改原始订单的状态
        updateOrderStatus(orderId,ProcessStatus.SPLIT);
        return orderInfoArrayList;
    }

    // 根据orderId 获取json 字符串
    private String initWareOrder(Long orderId) {
        //通过orderId获取orderInfo
        OrderInfo orderInfo = getOrderInfo(orderId);
        // 将orderInfo中部分数据转换为Map
        Map map = initWareOrder(orderInfo);

        return JSON.toJSONString(map);
    }

    //  将orderInfo中部分数据转换为Map
    public Map initWareOrder(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 仓库Id ，减库存拆单时需要使用！
    /*
    details:[{skuId:101,skuNum:1,skuName:
    ’小米手64G’},
    {skuId:201,skuNum:1,skuName:’索尼耳机’}]
     */
        //查询订单明细表
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<HashMap<String, Object>> mapArrayList = orderDetailList.stream().map(orderDetail -> {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId", orderDetail.getSkuId());
            orderDetailMap.put("skuNum", orderDetail.getSkuNum());
            orderDetailMap.put("skuName", orderDetail.getSkuName());
            return orderDetailMap;
        }).collect(Collectors.toList());
        map.put("details", mapArrayList);
        return map;
    }
}
